package IC;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;

import java_cup.runtime.Symbol;

import IC.AST.ASTNode;
import IC.AST.ASTPrinter;
import IC.Lexer.Lexer;
import IC.Lexer.LexicalError;
import IC.Parser.LibraryParser;
import IC.Parser.Parser;
import IC.Parser.SyntaxError;

/**
 * Main Compiler Class
 */
public class Compiler {

    
    public static String sourceFileName = "";
    public static String libFileName = "";
    
    @Option(name="-print-ast",usage="print the ast structure")
    private boolean isPrintAST;
    
    @Option(name="-print-tokens",usage="print the tokens")
    private boolean isPrintTokens;

    @Option(name="-L",usage="library file")
    private String libFilePath;

    
    @Argument
    private List<String> arguments = new ArrayList<String>();
    
    public void doMain(String[] args) throws IOException {
        CmdLineParser parser = new CmdLineParser(this);
      
        parser.setUsageWidth(80);

        try {
            // parse the arguments.
            parser.parseArgument(args);

            if( arguments.isEmpty() )
                throw new CmdLineException("No argument is given");

        } catch( CmdLineException e ) {
            System.out.println(e.getMessage());
            System.out.println("Usage: java IC.Compiler <file.ic> [ -L </path/to/libic.sig> ] [ options ] \n " +
            		"Option list: -print-ast, -print-tokens");
            // print the list of available options
            parser.printUsage(System.out);
            System.out.println();
            System.exit(1);
        }
        
        sourceFileName = arguments.get(0);
        libFileName = libFilePath;

    }
	
	public static void main(String[] args) {
		
		Compiler c = new Compiler();
		try {
			c.doMain(args);
		} catch (IOException e2) {
			e2.printStackTrace();
		}
		
		/**
		 * read input the file
		 */
		FileReader sourceFile = null;
		FileReader libFile = null;
		try {
			if(c.libFilePath != null) {
				libFile = new FileReader(c.libFilePath);
			}
			
			sourceFile = new FileReader(c.arguments.get(0));
		} catch (FileNotFoundException e1) {
			System.err.println("Could not open input file");
			System.exit(-1);
		}

		/**
		 * make the AST
		 */
		try {
			String sep = "";
			Symbol libParseTree = null;
			if (libFile != null) {
				Lexer libScanner = new Lexer(libFile);
				LibraryParser libParser = new LibraryParser(libScanner);
				if(c.isPrintTokens) {
					libParser.printTokens = true;
					sep = "\n ------- \n\n";
				}
				libParseTree = libParser.parse();
				System.out.print(sep);
				System.out.println("Parsed file "+ Compiler.libFileName +" successfully");
			}
			
			Lexer scanner = new Lexer(sourceFile);
			Parser parser = new Parser(scanner);
			if(c.isPrintTokens) {
				parser.printTokens = true;
			}
			Symbol parseTree = parser.parse();
			System.out.println("Parsed file "+ Compiler.sourceFileName +" successfully");
			
			System.out.print(sep);

			if (c.isPrintAST) {
				if (libFile != null) {
					ASTNode libRoot = (ASTNode) libParseTree.value;
					ASTPrinter libPrinter = new ASTPrinter(libRoot);
					libPrinter.print();
					
					System.out.println("\n ------- \n");
				}
				
				ASTNode root = (ASTNode) parseTree.value;
				ASTPrinter printer = new ASTPrinter(root);
				printer.print();
			}
		} catch (LexicalError e) {
			System.out.println(e.getMessage());
			return;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SyntaxError e) {
			System.out.print("error");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
